package com.biodiv.miracle.ioc.context;

import com.biodiv.miracle.aop.aspect.AspectObject;
import com.biodiv.miracle.ioc.core.BeanFactory;
import com.biodiv.miracle.ioc.factory.FactoryBeanRegister;
import com.biodiv.miracle.ioc.factory.FactoryBean;
import com.biodiv.miracle.ioc.processor.*;
import com.biodiv.miracle.support.annotation.*;
import com.biodiv.miracle.ioc.BeanDefinition;
import com.biodiv.miracle.ioc.factory.DefaultBeanFactory;
import com.biodiv.miracle.event.core.EventSourceManager;
import com.biodiv.miracle.event.core.EventListener;
import com.biodiv.miracle.event.ErrorEvent;
import com.biodiv.miracle.event.listener.ErrorEventListener;
import com.biodiv.miracle.event.PrintEvent;
import com.biodiv.miracle.event.listener.PrintEventListener;
import com.biodiv.miracle.event.ContextRefreshedEvent;
import com.biodiv.miracle.event.listener.ContextRefreshedEventListener;
import com.biodiv.miracle.support.utils.AnnotationUtils;
import com.biodiv.miracle.support.utils.MiracleUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.*;
import java.util.logging.Logger;

/**
 * @Author: tianquan
 * @CreateTime: 2024-09-30  11:16
 * @Description: 抽象应用上下文类，实现了应用上下文接口 提供了一些默认的实现，以及应用上下文初始化和Bean处理的基础设施
 */
public abstract class AbstractApplicationContext implements ApplicationContext {

    private final Logger logger = Logger.getLogger(AbstractApplicationContext.class.getName());
    protected Class<?> clazz;
    protected String[] args;
    private long startTime;
    protected final DefaultBeanFactory beanFactory;
    protected final EventSourceManager eventSourceManager;
    protected final List<Class<FactoryBeanRegister>> factoryBeanRegisterClassList;

    protected AbstractApplicationContext() {
        this.beanFactory = new DefaultBeanFactory();
        this.eventSourceManager = new EventSourceManager();
        this.factoryBeanRegisterClassList = new ArrayList<>();
    }

    @Override
    public void refresh() {
        startTime = System.currentTimeMillis();
        MiracleUtils.registerBean("applicationContext", this);
        // 添加框架最基础的BeanPostProcessor
        preBeanPostProcessor(beanFactory);
        try {
            // 拓展，初始化后置处理器
            postProcessBeanFactory(beanFactory);
            // 注册监听器
            registerListeners(eventSourceManager);
            // 拓展，在添加bean之前做的事
            preBeanInitialization(beanFactory);
            // 扫描包添加Bean定义对象
            initBeanDefinition(beanFactory);
            // 扫描BeanPostProcessor
            registryProcessorBean(beanFactory);
            // 创建bean放入容器中
            finishBeanFactoryInitialization(beanFactory);
            // 刷新容器后
            postRefresh(beanFactory, eventSourceManager);
        } catch (Exception e) {
            eventSourceManager.publishEvent(new ErrorEvent(this, e));
            throw new RuntimeException(e);
        }
    }

    protected void preBeanPostProcessor(DefaultBeanFactory beanFactory) {
        List<BeanPostProcessor> beanPostProcessors = beanFactory.getBeanPostProcessors();
        beanPostProcessors.add(new AutowiredBeanPostProcessor());
        beanPostProcessors.add(new InstanceBeanPostProcessor());
        beanPostProcessors.add(new PostConstructBeanPostProcessor());
        beanPostProcessors.add(new ResourceBeanPostProcessor());
        beanPostProcessors.add(new PoxyBeanPostProcessor(beanFactory.getProxyBeanFactory()));
    }

    protected void postProcessBeanFactory(DefaultBeanFactory beanFactory) {
    }

    protected void registerListeners(EventSourceManager eventSourceManager) {
        // 加载框架需要的监听器
        eventSourceManager.addEventListener(new PrintEventListener());
        eventSourceManager.addEventListener(new ContextRefreshedEventListener());
        eventSourceManager.addEventListener(new ErrorEventListener());
        // 发布打印事件
        eventSourceManager.publishEvent(new PrintEvent(this));
    }

    protected void postRefresh(DefaultBeanFactory beanFactory, EventSourceManager eventSourceManager) {
        // 将实现了EventListener接口的类注册到监听器管理者里面
        List<EventListener> eventListeners = beanFactory.getBeans(EventListener.class);
        logger.info("自定义监听器列表：" + eventListeners);
        eventSourceManager.addEventListeners(eventListeners);
        // 发布容器启动完毕事件
        eventSourceManager.publishEvent(new ContextRefreshedEvent(this, startTime));
    }


    /**
     * 在Bean后处理器处理Bean之前执行的一些预处理操作
     *
     * @param defaultBeanFactory 默认的Bean工厂，用于注册和管理Bean
     */
    protected void preBeanInitialization(DefaultBeanFactory defaultBeanFactory) {
    }

    /**
     * 解析并创建切面Bean
     *
     * @param defaultBeanFactory 默认的Bean工厂，用于注册和管理Bean
     */
    protected void parseCreateAspectBean(DefaultBeanFactory defaultBeanFactory) {
        List<BeanDefinition> allBeanDefinition = defaultBeanFactory.getAllBeanDefinition();
        for (BeanDefinition beanDefinition : allBeanDefinition) {
            Class<?> aClass = beanDefinition.getaClass();
            Aspect annotation = aClass.getAnnotation(Aspect.class);
            if (annotation == null) {
                continue;
            }
            Method[] methods = aClass.getDeclaredMethods();
            // 创建切面类
            AspectObject aspectObject = new AspectObject();
            // 设置切面类
            aspectObject.setObject(MiracleUtils.getBean(aClass));
            Pointcut pointcut = null;
            Method poinctcutMethod = null;
            for (Method method : methods) {
                // 设置切点
                Pointcut var1 = method.getAnnotation(Pointcut.class);
                if (var1 != null && pointcut == null) {
                    pointcut = var1;
                    poinctcutMethod = method;
                }
                // 设置前置通知
                if (AnnotationUtils.parseMethod(method, Before.class) != null && aspectObject.getBeforeMethod() == null) {
                    aspectObject.setBeforeMethod(method);
                }
                // 设置环绕通知
                if (AnnotationUtils.parseMethod(method, Around.class) != null && aspectObject.getAroundMethod() == null) {
                    aspectObject.setAroundMethod(method);
                }
                // 设置后置通知
                if (AnnotationUtils.parseMethod(method, After.class) != null && aspectObject.getAfterMethod() == null) {
                    aspectObject.setAfterMethod(method);
                }
            }
            // 当前方法没有切点直接解析下一个bean定义对象
            if (pointcut == null) {
                continue;
            }
            // 判断切点方法是否为空
            if (aspectObject.getBeforeMethod() == null && aspectObject.getAfterMethod() == null && aspectObject.getAroundMethod() == null) {
                continue;
            }
            // 判断切点方法和通知上面的方法是否一致
            AnnotationUtils.cheekAnnotation(aspectObject, poinctcutMethod.getName());
            // 设置需要代理的方法
            String[] methodList = pointcut.method();
            if (methodList != null && methodList.length > 0) {
                Arrays.stream(methodList).forEach(method -> defaultBeanFactory.putAopMethodsName(method, aspectObject));
            }
            // 设置需要代理的类
            Class<?>[] classes = pointcut.classArray();
            if (classes != null && classes.length > 0) {
                Arrays.stream(classes).forEach(classProxy -> defaultBeanFactory.putAopClass(classProxy, aspectObject));
            }
            // 设置需要代理的注解
            Class<? extends Annotation>[] annotations = pointcut.annotation();
            if (annotations != null && annotations.length > 0) {
                Arrays.stream(annotations).forEach(a -> defaultBeanFactory.putAopAnnotationName(a, aspectObject));
            }
        }
    }

    /**
     * 将自定义的BeanPostProcessor注册到容器中
     *
     * @param defaultBeanFactory 默认的Bean工厂，用于注册和管理Bean
     */
    protected void registryProcessorBean(DefaultBeanFactory defaultBeanFactory) {
        List<BeanDefinition> allBeanDefinition = defaultBeanFactory.getAllBeanDefinition();
        for (BeanDefinition beanDefinition : allBeanDefinition) {
            Class<?> aClass = beanDefinition.getaClass();
            if (clazz == null) {
                continue;
            }
            // 判断该class有没有实现BeanPostProcessor接口
            if (BeanPostProcessor.class.isAssignableFrom(aClass)) {
                // 先实例化该类 将该类放入BeanPostProcessor容器里
                BeanPostProcessor beanPostProcessor = (BeanPostProcessor) defaultBeanFactory.getBean(aClass);
                defaultBeanFactory.addBeanPostProcessor(beanPostProcessor);
            }
        }
    }

    /**
     * 排除不需要自动配置的类
     */
    protected void excludeNoAutoConfiguration(BeanFactory beanFactory) {
        //  排除掉用户不需要自动配置的类
    }

    /**
     * 初始化Bean定义
     *
     * @param defaultBeanFactory 默认的Bean工厂，用于注册和管理Bean
     */
    protected void initBeanDefinition(DefaultBeanFactory defaultBeanFactory) {
        // 找到@Component注解的类
        List<Class<?>> classList = findClassesInPackageAndSubpackages().stream().filter(AnnotationUtils::scanComponentClass).toList();

        // 生成Bean定义对象
        for (Class<?> clazz : classList) {
            // 找到类上有包含@Component注解的注解
            String beanName = null;
            for (Annotation annotation : clazz.getAnnotations()) {
                boolean isComponent = AnnotationUtils.hasMetaAnnotation(annotation.annotationType(), Component.class);
                if (isComponent) {
                    // 根据注解或者class名称创建bean名称
                    beanName = MiracleUtils.createBeanName(annotation, clazz);
                }
            }
            if (beanName == null) {
                MiracleUtils.createBeanName(clazz);
            }
            // 向容器中添加Bean定义对象
            BeanDefinition beanDefinition = new BeanDefinition(beanName, clazz, "singleton");
            defaultBeanFactory.registerBeanDefinition(beanName, beanDefinition);
        }

        // 解析@Import注解的类
        for (Class<?> clazz : classList) {
            List<Import> imports = AnnotationUtils.getAnnotations(clazz, Import.class);
            for (Import anImport : imports) {
                // 获取@Import注解中需要导入的类
                for (Class<?> improtClass : anImport.value()) {
                    // 注册需要导入的Bean定义对象
                    String beanName = MiracleUtils.createBeanName(improtClass);
                    BeanDefinition beanDefinition = new BeanDefinition(beanName, improtClass, "singleton");
                    defaultBeanFactory.registerBeanDefinition(beanName, beanDefinition);
                    // class是否实现了FactoryBeanRegister
                    if (FactoryBeanRegister.class.isAssignableFrom(improtClass)) {
                        factoryBeanRegisterClassList.add((Class<FactoryBeanRegister>) improtClass);
                    }
                }
            }
        }

        // 添加beanFactory
        for (Class<FactoryBeanRegister> factoryBeanRegisterClass : factoryBeanRegisterClassList) {
            try {
                FactoryBeanRegister factoryBeanRegister = factoryBeanRegisterClass.newInstance();
                // 获取到FactoryBean实例
                Collection<FactoryBean<?>> factoryBeans = factoryBeanRegister.scanFactoryBean(clazz,this);
                for (FactoryBean<?> factoryBean : factoryBeans) {
                    Class<?> objectType = factoryBean.getObjectType();
                    String beanName = MiracleUtils.createBeanName(null, objectType);

                    // beanFactory产出的bean
                    BeanDefinition beanDefinition = new BeanDefinition(beanName, objectType, "singleton");
                    beanDefinition.setFactoryBean(factoryBean);
                    defaultBeanFactory.registerBeanDefinition(beanName, beanDefinition);

                    // 添加beanFactory
                    BeanDefinition beanDefinition1 = new BeanDefinition("&" + objectType.getSimpleName(), factoryBeans.getClass(), "singleton");
                    defaultBeanFactory.registerBeanDefinition(beanDefinition1.getBeanName(), beanDefinition1);
                }

            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        // 排除不需要自动配置的类
        excludeNoAutoConfiguration(beanFactory);

        // 解析加有aspect注解的类
        parseCreateAspectBean(beanFactory);
    }

    private void initOrdinaryBeanDefinition(DefaultBeanFactory defaultBeanFactory, List<Class<?>> classList) {
        // 生成Bean定义对象
        for (Class<?> clazz : classList) {
            // 找到类上有包含@Component注解的注解
            String beanName = null;
            for (Annotation annotation : clazz.getAnnotations()) {
                boolean isComponent = AnnotationUtils.hasMetaAnnotation(annotation.annotationType(), Component.class);
                if (isComponent) {
                    // 根据注解或者class名称创建bean名称
                    beanName = MiracleUtils.createBeanName(annotation, clazz);
                }
            }
            if (beanName == null) {
                MiracleUtils.createBeanName(clazz);
            }
            // 向容器中添加Bean定义对象
            BeanDefinition beanDefinition = new BeanDefinition(beanName, clazz, "singleton");
            defaultBeanFactory.registerBeanDefinition(beanName, beanDefinition);
        }
    }

    /**
     * 解析Import注解
     *
     * @param defaultBeanFactory 默认的Bean工厂，用于注册和管理Bean
     * @param clazz              当前处理的类
     */
    private void parseImport(DefaultBeanFactory defaultBeanFactory, Class<?> clazz) {


    }

    /**
     * 初始化Beans
     *
     * @param defaultBeanFactory 默认的Bean工厂，用于注册和管理Bean
     */
    void finishBeanFactoryInitialization(DefaultBeanFactory defaultBeanFactory) {
        defaultBeanFactory.loadBean();
    }

    /**
     * 在Bean后处理器处理Bean之后执行的一些操作
     *
     * @param defaultBeanFactory 默认的Bean工厂，用于注册和管理Bean
     * @param eventSourceManager 事件源管理器，用于管理事件监听器
     */
    public void postBeanPostProcessor(DefaultBeanFactory defaultBeanFactory, EventSourceManager eventSourceManager) {
        // 将实现了EventListener接口的类注册到监听器管理者里面
        List<EventListener> eventListeners = defaultBeanFactory.getBeans(EventListener.class);
        logger.info("监听器列表：" + eventListeners);
        eventSourceManager.addEventListeners(eventListeners);
    }

    /**
     * 找到并返回指定包及其子包中的所有类
     *
     * @return 包含所有类的列表
     */
    protected abstract List<Class<?>> findClassesInPackageAndSubpackages();

}

